/**************************************************************************************************
	$Header: /pub/cvsroot/mydns/src/lib/mydns.h,v 1.73 2003/07/25 09:26:45 bboy Exp $
	libmydns.h: Header file for the MyDNS library.

	Copyright (C) 2002-2003  Don Moore <bboy@bboy.net>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at Your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#ifndef _MYDNS_H
#define _MYDNS_H

#include "mydnsutil.h"
#include "bits.h"
#include "header.h"

/* Table names */
#define	MYDNS_SOA_TABLE	"soa"
#define	MYDNS_RR_TABLE		"rr"

/* Configurable table names */
extern char mydns_soa_table_name[PATH_MAX];
extern char mydns_rr_table_name[PATH_MAX];

/* Configurable WHERE clauses */
extern char *mydns_soa_where_clause;
extern char *mydns_rr_where_clause;

/* If this is nonzero, an 'active' field is assumed to exist in the table, and
	only active rows will be loaded by mydns_*_load() */
extern int mydns_soa_use_active;
#define mydns_set_soa_use_active(S)	\
				(mydns_soa_use_active = sql_iscolumn((S), mydns_soa_table_name, "active"))
extern int mydns_rr_use_active;
#define mydns_set_rr_use_active(S)	\
				(mydns_rr_use_active = sql_iscolumn((S), mydns_rr_table_name, "active"))

/* This is set by mydns_set_soa_use_xfer */
extern int mydns_soa_use_xfer;
#define mydns_set_soa_use_xfer(S)	\
				(mydns_soa_use_xfer = sql_iscolumn((S), mydns_soa_table_name, "xfer"))

/* This is set by mydns_set_rr_use_stamp (currently unimplemented - for future IXFR support */
extern int mydns_rr_use_stamp;
#define mydns_set_rr_use_stamp(S)	\
				(mydns_rr_use_stamp = sql_iscolumn((S), mydns_rr_table_name, "stamp"))

/* NOTE: `type' is listed at the end so that we can possibly set the value of `aux' for
	convenience based on the RR type; for example, an `A' record might store the IP in `aux'. */
#define	MYDNS_SOA_NUMFIELDS	10
#define	MYDNS_SOA_FIELDS		"id,origin,ns,mbox,serial,refresh,retry,expire,minimum,ttl"

#define	MYDNS_RR_NUMFIELDS	7
#define	MYDNS_RR_FIELDS		"id,zone,name,data,aux,ttl,type"

/* Does the specified string end with a dot? */
#define	ENDS_WITH_DOT(s)	(s && (s[strlen(s)-1] == '.'))

/* Convert str to unsigned int */
#define atou(s) (uint32_t)strtoul(s, (char **)NULL, 10)

/* Size ranges for various bits of DNS data */
#define	DNS_MAXPACKETLEN_TCP		65536		/* Use 64k for TCP */
#define	DNS_MAXPACKETLEN_UDP		512		/* RFC1035: "512 octets or less" */
#define	DNS_MAXNAMELEN				255		/* RFC1035: "255 octets or less" */
#define	DNS_MAXESC					DNS_MAXNAMELEN + DNS_MAXNAMELEN + 1
#define	DNS_MAXLABELLEN			63			/* RFC1035: "63 octets or less" */
#define	DNS_POINTER_MASK			0xC0
#define	DNS_QUERYBUFSIZ			512		/* Used as buffer size for SQL queries */

/* Default values in SOA records */
#define	DNS_DEFAULT_REFRESH		28800
#define	DNS_DEFAULT_RETRY			7200
#define	DNS_DEFAULT_EXPIRE		604800
#define	DNS_DEFAULT_MINIMUM		86400
#define	DNS_DEFAULT_TTL			86400
#define	DNS_MINIMUM_TTL			300

/* Information about the PTR suffix */
/* #define	PTR_SUFFIX					".in-addr.arpa." */
/* #define	PTR_SUFFIX_LEN				14 */

/* Macro to convert quads into address -- result like MySQL's INET_ATON() */
#define INET_ATON(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))


/* Common errors */
typedef enum _task_error_t {
	ERR_NONE = 0,						/* No error */
	ERR_ZONE_NOT_FOUND,				/* "Zone not found" */
	ERR_NO_MATCHING_RECORDS,		/* "No matching resource records" */
	ERR_NO_AXFR,						/* "AXFR disabled" */
	ERR_RR_NAME_TOO_LONG,			/* "Name too long in RR" */
	ERR_RR_LABEL_TOO_LONG,			/* "Label too long in RR" */
	ERR_Q_BUFFER_OVERFLOW,			/* "Input name buffer overflow" */
	ERR_Q_INVALID_COMPRESSION,		/* "Invalid compression method" */
	ERR_Q_NAME_TOO_LONG,				/* "Question name too long" */
	ERR_NO_CLASS,						/* "Unknown class" */
	ERR_NAME_FORMAT,					/* "Invalid name format" */
	ERR_TIMEOUT,						/* "Communications timeout" */
	ERR_BROKEN_GLUE,					/* "Malformed glue" */
	ERR_INVALID_ADDRESS,				/* "Invalid address" */
	ERR_DB_ERROR,						/* "Database error" */
	ERR_NO_QUESTION,					/* "No question in query" */
	ERR_QUESTION_TRUNCATED,			/* "Question truncated" */
	ERR_UNSUPPORTED_OPCODE,			/* "Unsupported opcode" */
	ERR_MALFORMED_REQUEST,			/* "Malformed request" */
	ERR_AXFR_NOT_ENABLED,			/* "AXFR not enabled" */
	ERR_TCP_NOT_ENABLED,				/* "TCP not enabled" */
} task_error_t;

/* Query classes */
typedef enum _dns_class_t
{
	DNS_C_IN = 1,
	DNS_C_CHAOS = 3,
	DNS_C_HESIOD = 4,
	DNS_C_ANY = 255
} dns_class_t;

/* Query types */
typedef enum _dns_qtype_t
{
	DNS_T_NONE = 0,				/* None/invalid */
	DNS_T_A = 1,					/* Address */
	DNS_T_NS = 2,					/* Nameserver */
	DNS_T_MD = 3,					/* Mail dest */
	DNS_T_MF = 4,					/* Mail forwarder */
	DNS_T_CNAME = 5,				/* Canonical name */
	DNS_T_SOA = 6,					/* Start of authority */
	DNS_T_MB = 7,					/* Mailbox name */
	DNS_T_MG = 8,					/* Mail group */
	DNS_T_MR = 9,					/* Mail rename */
	DNS_T_NULL = 10,				/* Null */
	DNS_T_WKS = 11,				/* Well known service */
	DNS_T_PTR = 12,				/* IP -> fqdn mapping */
	DNS_T_HINFO = 13,				/* Host info */
	DNS_T_MINFO = 14,				/* Mailbox info */
	DNS_T_MX = 15,					/* Mail routing info */
	DNS_T_TXT = 16,				/* Text */
	DNS_T_RP = 17,					/* Responsible person */
	DNS_T_AFSDB = 18,				/* AFS cell database */
	DNS_T_X25 = 19,				/* X_25 calling address */
	DNS_T_ISDN = 20,				/* ISDN calling address */
	DNS_T_RT = 21,					/* Router */
	DNS_T_NSAP = 22,				/* NSAP address */
	DNS_T_NSAP_PTR = 23,			/* Reverse NSAP lookup (depreciated) */
	DNS_T_SIG = 24,				/* Security signature */
	DNS_T_KEY = 25,				/* Security key */
	DNS_T_PX = 26,					/* X.400 mail mapping */
	DNS_T_GPOS = 27,				/* Geographical position (withdrawn) */
	DNS_T_AAAA = 28,				/* IPv6 Address */
	DNS_T_LOC = 29,				/* Location info */
	DNS_T_NXT = 30,				/* Next domain (security) */
	DNS_T_EID = 31,				/* Endpoint identifier */
	DNS_T_NIMLOC = 32,			/* Nimrod Locator */
	DNS_T_SRV = 33,				/* Server */
	DNS_T_ATMA = 34,				/* ATM Address */
	DNS_T_NAPTR = 35,				/* Naming Authority Pointer */
	DNS_T_KX = 36,					/* Key Exchange */
	DNS_T_CERT = 37,				/* Certification record */
	DNS_T_A6 = 38,					/* IPv6 address (deprecates AAAA) */
	DNS_T_DNAME = 39,				/* Non-terminal DNAME (for IPv6) */
	DNS_T_SINK = 40,				/* Kitchen sink (experimentatl) */
	DNS_T_OPT = 41,				/* EDNS0 option (meta-RR) */
	DNS_T_TSIG = 250,				/* Transaction signature */
	DNS_T_IXFR = 251,				/* Incremental zone transfer */
	DNS_T_AXFR = 252,				/* Zone transfer */
	DNS_T_MAILB = 253,			/* Transfer mailbox records */
	DNS_T_MAILA = 254,			/* Transfer mail agent records */
	DNS_T_ANY = 255,				/* Any */

#if ALIAS_ENABLED
	DNS_T_ALIAS = 500,			/* Extension - David Phillips, alias patch */
#endif

	DNS_T_MAX = 65536
} dns_qtype_t;


/* Opcodes */
typedef enum _dns_opcode_t		/* DNS opcode types */
{
	DNS_OPCODE_QUERY = 0,		/* Query */
	DNS_OPCODE_IQUERY,			/* Inverse query */
	DNS_OPCODE_STATUS				/* Status request */
} dns_opcode_t;


/* Return codes */
typedef enum _dns_rcode_t		/* DNS return codes */
{
	DNS_R_NOERROR = 0,			/* No error */
	DNS_R_FORMERR = 1,			/* The name server was unable to interpret the query */
	DNS_R_SERVFAIL = 2,			/* The name server had an internal error */
	DNS_R_NXDOMAIN = 3,			/* The specified domain name does not exist */
	DNS_R_NOTIMP = 4,				/* The requested kind of query is not implemented */
	DNS_R_REFUSED = 5,			/* Query refused for policy reasons */
	DNS_R_YXDOMAIN = 6,			/* ??? */
	DNS_R_YXRRSET = 7,			/* ??? */
	DNS_R_NXRRSET = 8,			/* ??? */
	DNS_R_NOTAUTH = 9,			/* Not authoritative? */
	DNS_R_NOTZONE = 10,			/* ??? */
	DNS_R_BADVERS = 16,			/* ??? */
} dns_rcode_t;

/* The record types */
typedef enum _dns_rrtype_t		/* DNS record types (for MyDNS) */
{
	DNS_RRTYPE_SOA,
	DNS_RRTYPE_RR
} dns_rrtype_t;


/*
**  Structures describing each record type
*/
typedef struct _mydns_soa							/* `soa' table data (zones of authority) */
{
	uint32_t		id;
	char			origin[DNS_MAXNAMELEN+1];
	char			ns[DNS_MAXNAMELEN+1];
	char			mbox[DNS_MAXNAMELEN+1];
	uint32_t		serial;
	uint32_t		refresh;
	uint32_t		retry;
	uint32_t		expire;
	uint32_t		minimum;
	uint32_t		ttl;

	struct _mydns_soa *next;
} MYDNS_SOA;

typedef struct _mydns_rr							/* `rr' table data (resource records) */
{
	uint32_t		id;
	uint32_t		zone;
	char			name[DNS_MAXNAMELEN+1];
	dns_qtype_t	type;
	char			data[DNS_MAXNAMELEN+1];
	uint32_t		aux;
	uint32_t		ttl;
#if ALIAS_ENABLED
	int			alias;
#endif

	/* This data used by SRV records only - parsed (and removed) from "data" */
	uint16_t		srv_weight, srv_port;

	struct _mydns_rr *next;
} MYDNS_RR;


/* sql.c */
#if USE_PGSQL
typedef PGconn SQL;
typedef unsigned char ** SQL_ROW;
typedef struct _sql_res {
	PGresult *result;
	int		tuples;
	int		fields;
	int		current_tuple;
	SQL_ROW	current_row;
} SQL_RES;
#else
typedef MYSQL SQL;
typedef MYSQL_RES SQL_RES;
typedef MYSQL_ROW SQL_ROW;
#endif



/* ip.c */
extern uint32_t	mydns_revstr_ip4(char *);
extern int			mydns_extract_arpa(char *, uint8_t ip[]);


/* rr.c */
extern long			mydns_rr_count(SQL *);
extern void			mydns_set_rr_table_name(char *);
extern void			mydns_set_rr_where_clause(char *);
extern MYDNS_RR	*mydns_parse_rr(SQL_ROW, const char *);
extern int			mydns_rr_load(SQL *, MYDNS_RR **, uint32_t, dns_qtype_t, char *, char *);
extern MYDNS_RR	*mydns_rr_dup(MYDNS_RR *, int);
extern size_t		mydns_rr_size(MYDNS_RR *);
extern void			_mydns_rr_free(MYDNS_RR *);
#define mydns_rr_free(p) if (p) _mydns_rr_free(p), p = NULL


/* soa.c */
extern long			mydns_soa_count(SQL *);
extern void			mydns_set_soa_table_name(char *);
extern void			mydns_set_soa_where_clause(char *);
extern MYDNS_SOA	*mydns_parse_soa(SQL_ROW);
extern int			mydns_soa_load(SQL *, MYDNS_SOA **, char *);
extern int			mydns_soa_make(SQL *, MYDNS_SOA **, unsigned char *, unsigned char *);
extern MYDNS_SOA	*mydns_soa_dup(MYDNS_SOA *, int);
extern size_t		mydns_soa_size(MYDNS_SOA *);
extern void			_mydns_soa_free(MYDNS_SOA *);
#define mydns_soa_free(p) if (p) _mydns_soa_free(p), p = NULL


/* sql.c */
extern SQL		*sql;
extern void		sql_open(char *user, char *password, char *host, char *database);
extern void		sql_reopen(void);
extern void		_sql_close(SQL *);
#define sql_close(p) if (p) _sql_close(p), p = NULL
extern int		sql_nrquery(SQL *, const char *query, size_t querylen);
extern SQL_RES	*sql_query(SQL *, const char *query, size_t querylen);
extern SQL_RES	*sql_queryf(SQL *, const char *, ...) __printflike(2,3);
extern long		sql_count(SQL *, const char *, ...) __printflike(2,3);
extern SQL_ROW	sql_getrow(SQL_RES *res);
extern void		sql_escstr(SQL *, char *, char *, size_t);
extern void		_sql_free(SQL_RES *res);
extern long		sql_num_rows(SQL_RES *res);
extern int		sql_istable(SQL *, const char *);
extern int		sql_iscolumn(SQL *, const char *, const char *);
#define sql_free(p) if (p) _sql_free(p), p = NULL


/* str.c */
extern char		*mydns_qtype_str(dns_qtype_t);
extern char		*mydns_class_str(dns_class_t);
extern char		*mydns_opcode_str(dns_opcode_t);
extern char		*mydns_rcode_str(dns_rcode_t);


/* unencode.c */
extern char		*name_unencode(char *, size_t, char *, char *, size_t);


#endif /* !_MYDNS_H */

/* vi:set ts=3: */
